
// import oimo.common.Transform;
// import oimo.collision.broadphase.BroadPhase;
// import oimo.collision.broadphase.Proxy;
// import oimo.collision.geometry.ConvexGeometry;
// import oimo.m.Vec3;
// import oimo.m.M;
// import oimo.common.Vec3;
// import oimo.collision.broadphase.*;
// import oimo.collision.geometry.Aabb;

import { BroadPhase } from "../BroadPhase";
import { M } from "../../../common/M";
import { Aabb } from "../../geometry/Aabb";
import { Vec3 } from "../../../common/Vec3";
import { BroadPhaseProxyCallback } from "../BroadPhaseProxyCallback";
import { ConvexGeometry } from "../../geometry/ConvexGeometry";
import { Transform } from "../../../common/Transform";
import { BroadPhaseType } from "../BroadPhaseType";
import { Proxy } from "../Proxy";

/**
 * Brute force implementation of broad-phase collision detection. Time complexity is O(n^2).
 */

export class BruteForceBroadPhase extends BroadPhase {


	constructor() {
		super(BroadPhaseType.BRUTE_FORCE);
		this._incremental = false;
	}

	// --- ---


	private overlap(p1: Proxy, p2: Proxy): boolean {
		return M.aabb_overlap(p1._aabbMin, p1._aabbMax, p2._aabbMin, p2._aabbMax);
	}

	// --- public ---

	public createProxy(userData: any, aabb: Aabb): Proxy {
		var proxy: Proxy = new Proxy(userData, this._idCount++);
		this.addProxy(proxy);

		proxy._setAabb(aabb);
		return proxy;
	}

	public destroyProxy(proxy: Proxy): void {
		this.removeProxy(proxy);

		proxy.userData = null;
	}

	public moveProxy(proxy: Proxy, aabb: Aabb, dislacement: Vec3): void {
		proxy._setAabb(aabb);
	}

	public collectPairs(): void {
		this.poolProxyPairs();
		this._testCount = 0;
		var p1: Proxy = this._proxyList;
		while (p1 != null) {
			var p2: Proxy = p1._next;
			while (p2 != null) {
				this._testCount++;
				if (this.overlap(p1, p2)) {
					this.pickAndPushProxyPair(p1, p2);
				}
				p2 = p2._next;
				p1 = p1._next;
			}
		};
	}

	public rayCast(begin: Vec3, end: Vec3, callback: BroadPhaseProxyCallback): void {
		var p1: Vec3 = new Vec3();
		var p2: Vec3 = new Vec3();
		var dir: Vec3 = new Vec3();
		M.vec3_fromVec3(p1, begin);
		M.vec3_fromVec3(p2, end);
		M.vec3_sub(dir, p2, p1);

		var min: Vec3 = new Vec3();
		var max: Vec3 = new Vec3();
		M.vec3_min(min, p1, p2);
		M.vec3_max(max, p1, p2);

		var p: Proxy = this._proxyList;
		while (p != null) {
			if (this.aabbSegmentTest(p._aabbMin, p._aabbMax, p1, p2)) {
				callback.process(p);
			}
			p = p._next;
		}
	}

	public convexCast(convex: ConvexGeometry, begin: Transform, translation: Vec3, callback: BroadPhaseProxyCallback): void {
		var p: Proxy = this._proxyList;
		while (p != null) {
			if (this.aabbConvexSweepTest(p._aabbMin, p._aabbMax, convex, begin, translation)) {
				callback.process(p);
			}
			p = p._next;
		}

	}

	public aabbTest(aabb: Aabb, callback: BroadPhaseProxyCallback): void {
		var p: Proxy = this._proxyList;
		while (p != null) {
			if (M.aabb_overlap(aabb._min, aabb._max, p._aabbMin, p._aabbMax)) {
				callback.process(p);
			}
			p = p._next;
		}
	}

}
